﻿using System.Reflection;

using zijian666.Core.Abstractions;

namespace zijian666.Core
{
    /// <summary>
    /// 功能组件管理器
    /// </summary>
    public static class FeatureManager
    {
        /// <summary>
        /// 内置组件枚举
        /// </summary>
        private static readonly string[] AssemblyNames = new[]
        {
            "zijian666.DI",
            "zijian666.DI.Autowired",
            "zijian666.DI.NamedService",
            "zijian666.Converts",
            "zijian666.Converts.Json",
            "zijian666.Converts.Dynamic",
            "zijian666.DatabaseClientExtensions",
            "zijian666.HttpClientExtensions",
            "zijian666.HttpClientExtensions.Json",
            "zijian666.HttpClientExtensions.Convert",
            "zijian666.Core.Abstractions",
            "zijian666.AnyExtensions",
            "zijian666.AnyExtensions.ComponentModel",

            // 部分已过期
            "zijian666.SuperConvert",
            "zijian666.SuperConvert.Json",
            "zijian666.SuperConvert.Dynamic",
            "zijian666.SuperConvert.Mapping",
        };

        /// <summary>
        /// 判断类型是否可被实例化 <para/>
        /// 是值类型, 或 至少有一个公开构造函数的非抽象类/非静态类/非泛型定义类
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static bool Instantiable(Type type) =>
            type.IsValueType
            || (type.IsClass && !type.IsAbstract && !type.IsGenericTypeDefinition && type.GetConstructors().Length > 0);

        private static readonly ConcurrentList<FeatureDescription> _descriptions = new ConcurrentList<FeatureDescription>(null);

        static FeatureManager()
        {
            var resolver = AssemblyResolver.Default;

            foreach (var name in AssemblyNames)
            {
                try
                {
                    resolver.LoadFromAssemblyName(new AssemblyName(name));
                }
                catch (FileNotFoundException)
                {

                }
            }

            var descriptions = resolver.GetTypesWithAssignableFrom(typeof(IFeature))
                                .Where(Instantiable)
                                .Where(x => x.GetConstructor(Type.EmptyTypes) != null)
                                .Select(Activator.CreateInstance)
                                .Select(x => new FeatureDescription(x))
                                .ToList();

            _descriptions.ReplaceOrAdd(descriptions);

            foreach (var description in descriptions)
            {
                description.RefreshSlot();
            }
        }

        /// <summary>
        /// 注册
        /// </summary>
        public static void Register(object feature)
        {
            var description = new FeatureDescription(feature);
            if (_descriptions.Add(description))
            {
                foreach (var desc in _descriptions)
                {
                    if (desc == description)
                    {
                        continue;
                    }
                    if (desc.AutoRefreshSlot)
                    {
                        desc.RefreshSlot();
                    }
                }
                description.RefreshSlot();
            }
        }

        /// <summary>
        /// 移除
        /// </summary>
        public static void Remove(object feature)
        {
            if (_descriptions.RemoveIf(x => x.Feature.Equals(feature)) > 0)
            {
                foreach (var desc in _descriptions)
                {
                    if (desc.AutoRefreshSlot)
                    {
                        desc.RefreshSlot();
                    }
                }
            }
        }

        /// <summary>
        /// 获取功能组件, 如果不存在返回null
        /// </summary>
        public static T Get<T>(Predicate<T> predicate = null)
            where T : class
        {
            foreach (var description in _descriptions)
            {
                if (description.Feature is T t && (predicate == null || predicate(t)))
                {
                    return t;
                }
            }
            return null;
        }

        /// <summary>
        /// 获取功能组件, 如果不存在返回null
        /// </summary>
        public static object Get(Type featureType, Predicate<object> predicate = null)
        {
            foreach (var description in _descriptions)
            {
                if (description.IsInstanceOf(featureType) && (predicate == null || predicate(description.Feature)))
                {
                    return description.Feature;
                }
            }
            return null;
        }

        /// <summary>
        /// 获取功能组件, 如果不存在返回null
        /// </summary>
        public static IEnumerable<object> Gets(Type featureType, Predicate<object> predicate = null)
        {
            foreach (var description in _descriptions)
            {
                if (description.IsInstanceOf(featureType) && (predicate == null || predicate(description.Feature)))
                {
                    yield return description.Feature;
                }
            }
        }

        /// <summary>
        /// 获取功能组件, 如果不存在返回null
        /// </summary>
        public static IEnumerable<T> Gets<T>(Predicate<T> predicate = null)
            where T : class
        {
            foreach (var description in _descriptions)
            {
                if (description.Feature is T t && (predicate == null || predicate(t)))
                {
                    yield return t;
                }
            }
        }

        /// <summary>
        /// 获取功能组件, 如果不存在抛出异常
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static T GetRequired<T>(Predicate<T> predicate = null)
            where T : class
        {
            var feature = Get<T>(predicate);
            if (feature == null)
            {
                Throws.NotFoundFeature(typeof(T));
            }
            return feature;
        }

        /// <summary>
        /// 获取功能组件, 如果不存在抛出异常
        /// </summary>
        public static IEnumerable<T> GetsRequired<T>(Predicate<T> predicate = null)
            where T : class
        {
            var any = false;
            foreach (var description in _descriptions)
            {
                if (description.Feature is T t && (predicate == null || predicate(t)))
                {
                    any = true;
                    yield return t;
                }
            }
            if (!any)
            {
                Throws.NotFoundFeature(typeof(T));
            }
        }

        /// <summary>
        /// 装配
        /// </summary>
        public static void Wired(object instance)
        {
            if (instance == null)
            {
                return;
            }
            new FeatureDescription(instance).RefreshSlot();
        }

        /// <summary>
        /// 获取一个简易的 <seealso cref="IServiceProvider"/>
        /// </summary>
        public static IServiceProvider ServiceProvider { get; } = new FeatureServiceProvider();

        class FeatureServiceProvider : IServiceProvider
        {
            public object GetService(Type serviceType)
            {
                if (serviceType is null)
                {
                    throw new ArgumentNullException(nameof(serviceType));
                }
                if (serviceType.IsGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                {
                    return Gets(serviceType.GetGenericArguments()[0]);
                }
                return Get(serviceType);
            }
        }
    }
}
